package com.jic.utils;



import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Map;


@Component
public class RedisManager {
	private final Logger logger = LoggerFactory.getLogger(RedisManager.class);

//	RedisConfig redisConfig

	private JedisPool pool;
	
	// 最后发送时间
	private Long lastErrorTime;

//	@Value("${spring.redis.database}")
//	private int databaseIndex;

	@Value("${spring.redis.password}")
	private String password;

	@Value("${spring.redis.host}")
	private String masterHost;

	@Value("${spring.redis.port}")
	private int masterPort;

	@Value("${spring.redis.jedis.pool.max-active}")
	private int maxTotal;

	@Value("${spring.redis.jedis.pool.max-idle}")
	private int maxIdle;

	@Value("${spring.redis.jedis.pool.max-wait}")
	private int maxWait;


	private JedisPool getPool(){
		if(null == pool){
			synchronized(RedisManager.class){
				if(null == pool){
					JedisPoolConfig config = new JedisPoolConfig();
					config.setMaxTotal(maxTotal);
					config.setMaxIdle(maxIdle);
					config.setMaxWaitMillis(maxWait);
					config.setTestOnBorrow(true);
					config.setTestOnReturn(true);

					// 两种连接方式
					if(null == password ||password.length()==0){
						// 1、redis数据没有密码
						pool = new JedisPool(config, masterHost,
								masterPort, 3000);
					}else{
						// 2、redis数据有密码
						pool = new JedisPool(config, masterHost,
								masterPort,
								3000, password,0);
					}
				}
			}
		}
		return pool;
	}

	
	public Map<String,String> get(String key) throws Exception{
		logger.info("获取rediesMap:"+key);

		Jedis redis = null;
		Map<String, String> map = null;
		try {
			redis = getPool().getResource();
			map = redis.hgetAll(key); 
		} catch (Exception e) {
			//釋放redis对象
			getPool().returnBrokenResource(redis);
			logger.error("获取redis：" + key + "失败！");
			lastErrorTime=System.currentTimeMillis();
			throw new Exception(e);
		} finally {
			//返还到连接池
			if(redis != null)
				getPool().returnResource(redis);
		}
		return map;
	}
	
	/**
	 * Redis 查询，如果没有找到返回默认值
	 * @param key
	 * @param ifNUllDeafaul
	 * @return
	 * @throws Exception
	 */
	public String getString(String key,String ifNUllDeafaul) throws Exception{
		String str = getString(key);
		if(StringUtils.isBlank(str)){
			logger.error("Key: "+key+" 没有set值,采用默认值: "+ifNUllDeafaul);
			return ifNUllDeafaul;
		}else{
			return str;
		}
	}
	
	public String getString(String key) throws Exception{
		logger.info("获取redies String:"+key);
//		checkError();
		
		Jedis redis = null;
		String str = null;
		try {
			redis = getPool().getResource();
			str = redis.get(key);
		} catch (Exception e) {
			//釋放redis对象
			getPool().returnBrokenResource(redis);
			logger.error("获取redis：" + key + "失败！");
			lastErrorTime=System.currentTimeMillis();
			throw new Exception(e);
		} finally {
			//返还到连接池
			if(redis != null)
				getPool().returnResource(redis);
		}
		return str;
	}

	public void set(String key,Map<String,String> map) throws Exception{
		logger.info("key:" + key + ",map:" + map);
//		checkError();
		if (map == null){
			logger.info("map null");
		}else{
			Jedis redis = null;
			try {
				redis = pool.getResource();   
				redis.del(key);
				redis.hmset(key,map);
			} catch (Exception e) {
				//釋放redis对象
				pool.returnBrokenResource(redis);
				logger.error("入库redis：" + "key:" + key + ",map:" + map + "失败！");
				throw new Exception(e);
			} finally {
				//返还到连接池
				if(redis != null)
					pool.returnResource(redis);
			}
		}
	}
	
	public void setString(String key, String value) throws Exception{
		setString(key, value, 0);
	}
	
	public void setString(String key, String value, int seconds) throws Exception{
		logger.info("key:" + key + ",value:" + value);
//		checkError();
		if (StringUtils.isBlank(value)){
			logger.info("value is null or ''");
		}else{
			Jedis redis = null;
			try {
				redis = pool.getResource();   
				redis.del(key);
				if(seconds > 0)
					redis.setex(key, seconds, value);
				else
					redis.set(key, value);
			} catch (Exception e) {
				//釋放redis对象
				pool.returnBrokenResource(redis);
				logger.error("入库redis：" + "key:" + key + ",value:" + value + "失败！");
				throw new Exception(e);
			} finally {
				//返还到连接池
				if(redis != null)
					pool.returnResource(redis);
			}
		}
	}
	
	public void del(String key) throws Exception{
		logger.info("删除key:"+key);
//		checkError();
		Jedis redis = null;
		try {
			redis = pool.getResource(); 
			if(redis.exists(key)){
				redis.del(key);
			}
		} catch (Exception e) {
			//釋放redis对象
			pool.returnBrokenResource(redis);
			logger.error("删除redis：" + key + "失败！");
			throw new Exception(e);
		} finally {
			//返还到连接池
			if(redis != null)
				pool.returnResource(redis);
		}
	}
	
	public boolean exists(String key) throws Exception{
		logger.info("判断存在:"+key);
//		checkError();
		Jedis redis = null;
		boolean isexist = false;
		try {
			redis = pool.getResource(); 
			isexist = redis.exists(key);
		} catch (Exception e) {
			//釋放redis对象
			pool.returnBrokenResource(redis);
			logger.error("获取redis：" + key + "失败！");
			throw new Exception(e);
		} finally {
			//返还到连接池
			if(redis != null)
				pool.returnResource(redis);
		}
		return isexist;
	}
	
	/**
	 * redis 自动计数
	 * @param key
	 * @throws Exception 
	 */
	public long incr(String key) throws Exception{
		logger.info("计算器+1:"+key);
//		checkError();
		Jedis redis = null;
		try {
			redis = pool.getResource(); 
			return redis.incr(key);
		} catch (Exception e) {
			//釋放redis对象
			pool.returnBrokenResource(redis);
			logger.error("计数redis：" + key + "失败！");
			throw new Exception(e);
		} finally {
			//返还到连接池
			if(redis != null)
				pool.returnResource(redis);
		}
	}
	
	/**
	 * redis 设置过期时间
	 * @param key
	 * @param seconds
	 * @throws Exception 
	 */
	public void expire(String key,int seconds) throws Exception{
		logger.info("设置过期时间");
//		checkError();
		Jedis redis = null;
		try {
			redis = pool.getResource(); 
			redis.expire(key, seconds);
		} catch (Exception e) {
			//釋放redis对象
			pool.returnBrokenResource(redis);
			logger.error("redis设置过期时间" + key + "失败！");
			throw new Exception(e);
		} finally {
			//返还到连接池
			if(redis != null)
				pool.returnResource(redis);
		}
	}
	
	// 获取倒计时
	public String ttl(String key) throws Exception{
		Jedis redis = null;
		try {
			redis = pool.getResource(); 
			return String.valueOf(redis.ttl(key));
		} catch (Exception e) {
			//釋放redis对象
			pool.returnBrokenResource(redis);
			logger.error("redis查询过期时间异常");
			throw new Exception(e);
		} finally {
			//返还到连接池
			if(redis != null)
				pool.returnResource(redis);
		}
	}
	
	private void checkError() throws Exception{
		if(lastErrorTime!=null&&System.currentTimeMillis()-lastErrorTime<60000){
			logger.info("还在异常区间内返回异常");
			throw new Exception("还在错误时间范围内，直接返回！");
		}else if(lastErrorTime !=null ){
			lastErrorTime = null;
		}
	}
	
}
